﻿using Cinch;
using CodeSHARPer.AvalonEdit.Intellisense;
using CodeSHARPer.Model;
using CodeSHARPer.Services;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.CodeCompletion;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;

namespace CodeSHARPer.ViewModel.Dialogs
{
    public class CodeReferencesViewModel : ViewModelBase
    {
        ICSharpScriptProvider provider;
        ICSharpScriptProvider providerTemp;

        public CodeReferencesViewModel(ICSharpScriptProvider provider)
        {
            this.provider = provider;

            //commands
            this.BrowseReferenceCommand = new SimpleCommand<object, object>(DoBrowseReferenceCommand);
            this.AddFrameworkReferenceCommand = new SimpleCommand<object, object>(DoAddFrameworkReferenceCommand);
            this.RemoveReferenceCommand = new SimpleCommand<object, object>(CanRemoveReference, DoRemoveReferenceCommand);
            this.NuGetReferencesCommand = new SimpleCommand<object, object>(DoNuGetReferencesCommand);
        }

        #region Properties
        public bool HasChanges { get; set; }

        TextDocument mDocument;
        public TextDocument Document
        {
            get
            {
                if (mDocument == null)
                {
                    mDocument = new TextDocument();
                    mDocument.TextChanged += mDocument_TextChanged;
                    mDocument.Text = File.ReadAllText(this.FilePath);
                }
                return mDocument;
            }
            set
            {
                if (mDocument != value)
                {
                    mDocument = value;
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<CodeReferencesViewModel>(x => x.Document));
                }
            }
        }

        void mDocument_TextChanged(object sender, EventArgs e)
        {
            //TODO: HasChanges must only change when user alter text
            this.HasChanges = true;
        }

        string filePath;
        public string FilePath
        {
            get
            {
                if (string.IsNullOrEmpty(this.filePath))
                {
                    string path = Path.GetTempPath();
                    string filename = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
                    string complete = Path.Combine(path, filename + ".cs");

                    File.WriteAllText(complete, string.Format("{0}{2}{1}", JsonSerializer.Serialize(provider.Options), provider.GetNamespacesUsed(), Environment.NewLine));
                    this.filePath = complete;
                }
                return this.filePath;
            }
            private set
            {
                if (this.filePath != value)
                {
                    this.filePath = value;

                    NotifyPropertyChanged(ObservableHelper.CreateArgs<CodePadViewModel>(x => x.FilePath));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<CodePadViewModel>(x => x.CodeCompletion));
                }
            }
        }

        ObservableCollection<References> references;
        public ObservableCollection<References> UsedReferences
        {
            get
            {
                if (references == null)
                {
                    List<References> referencesList = new List<References>();
                    foreach (string assemblyName in provider.GetAssemblies())
                    {
                        referencesList.Add(new References(assemblyName));
                    }

                    references = new ObservableCollection<References>(referencesList);
                }
                return references;
            }
            set
            {
                references = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<CodeReferencesViewModel>(x => x.UsedReferences));
            }
        }

        References seletedReference;
        public References SeletedReference
        {
            get { return seletedReference; }
            set
            {
                seletedReference = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<CodeReferencesViewModel>(x => x.SeletedReference));
            }
        }

        CSharpCompletion codeCompletion;
        public CSharpCompletion CodeCompletion
        {
            get
            {
                if (codeCompletion == null)
                {
                    providerTemp = new ScriptProvider(this.FilePath);
                    codeCompletion = new ICSharpCode.CodeCompletion.CSharpCompletion(providerTemp);
                }
                return codeCompletion;
            }
            set
            {
                codeCompletion = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<CodeReferencesViewModel>(x => x.CodeCompletion));
            }
        }
        #endregion Properties

        #region Commands

        public SimpleCommand<object, object> BrowseReferenceCommand { get; set; }

        internal void DoBrowseReferenceCommand(object args)
        {
            Services.ServiceResolver.Instance.OpenFileService.Filter = "dll files (.dll)|*.dll|exe files (.exe)|*.exe";
            bool? result = Services.ServiceResolver.Instance.OpenFileService.ShowDialog(null);
            
            if (result.GetValueOrDefault())
            {
                this.HasChanges = true;
                string fileName = Services.ServiceResolver.Instance.OpenFileService.FileName;
                References r = new References(fileName);
                this.UsedReferences.Add(r);

                IEnumerable<string> referencesList =
                            from references in this.UsedReferences
                            where references.HasError == false
                            select references.Location;

                providerTemp.AlterReferences(referencesList.ToArray());
                CodeCompletion = new ICSharpCode.CodeCompletion.CSharpCompletion(providerTemp);
            }
        }

        public SimpleCommand<object, object> AddFrameworkReferenceCommand { get; set; }

        internal void DoAddFrameworkReferenceCommand(object args)
        {
            FrameworkAssembliesViewModel frameworkReferences = new FrameworkAssembliesViewModel();
            bool? result = ServiceResolver.Instance.UIVisualizerService.ShowDialog("FrameworkAssembliesView", frameworkReferences);

            if (result.GetValueOrDefault())
            {
                var seletedReferences = from r in frameworkReferences.UsedReferences
                                        where r.IsSeleted == true
                                        select r;

                foreach (var seletedReference in seletedReferences)
                {
                    seletedReference.IsSeleted = false;
                    this.UsedReferences.Add(seletedReference);
                }
            }
        }

        public SimpleCommand<object, object> RemoveReferenceCommand { get; set; }

        internal void DoRemoveReferenceCommand(object args)
        {
            var seletedReferences = from r in this.UsedReferences
                                    where r.IsSeleted == true
                                    select r;

            foreach (var seletedReference in seletedReferences.ToArray())
            {
                this.UsedReferences.Remove(seletedReference);
            }
        }

        internal bool CanRemoveReference(object args)
        {
            return this.UsedReferences != null && this.UsedReferences.Where(c => c.IsSeleted).Count() > 0;
        }

        public SimpleCommand<object, object> NuGetReferencesCommand { get; set; }

        internal void DoNuGetReferencesCommand(object args)
        {
            NuGetReferencesViewModel nuGetReferences = new NuGetReferencesViewModel();
            bool? result = ServiceResolver.Instance.UIVisualizerService.ShowDialog("NuGetReferencesView", nuGetReferences);

            if (result.GetValueOrDefault())
            {
                
            }
        }

        #endregion Commands
    }
}
